package service

import (
	"context"
	"fmt"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"

	"goldtree/internal/dao"
	"goldtree/internal/entity"
)

// StockPoolService 股票池服务
type StockPoolService struct{}

var StockPool = StockPoolService{}

// CreatePoolReq 创建股票池请求
type CreatePoolReq struct {
	Name        string `json:"name" v:"required|length:1,100#股票池名称不能为空|股票池名称长度不能超过100位"`
	Description string `json:"description"`
	Type        string `json:"type" v:"required|in:static,dynamic#股票池类型不能为空|股票池类型必须为static或dynamic"`
	MaxSize     int    `json:"max_size" v:"min:1|max:1000#最大股票数量必须大于0|最大股票数量不能超过1000"`
}

// UpdatePoolReq 更新股票池请求
type UpdatePoolReq struct {
	Id          int    `json:"id" v:"required|min:1#ID不能为空|ID必须大于0"`
	Name        string `json:"name" v:"required|length:1,100#股票池名称不能为空|股票池名称长度不能超过100位"`
	Description string `json:"description"`
	MaxSize     int    `json:"max_size" v:"min:1|max:1000#最大股票数量必须大于0|最大股票数量不能超过1000"`
	IsActive    *bool  `json:"is_active"`
}

// GetPoolListReq 获取股票池列表请求
type GetPoolListReq struct {
	Page     int    `json:"page" v:"min:1#页码必须大于0"`
	Limit    int    `json:"limit" v:"min:1|max:100#每页数量必须大于0|每页数量不能超过100"`
	Keyword  string `json:"keyword"`
	Type     string `json:"type"`
	IsActive *bool  `json:"is_active"`
}

// PoolListRes 股票池列表响应
type PoolListRes struct {
	List  []*entity.StockPool `json:"list"`
	Total int                 `json:"total"`
	Page  int                 `json:"page"`
	Limit int                 `json:"limit"`
}

// AddMemberReq 添加股票池成员请求
type AddMemberReq struct {
	PoolId    int     `json:"pool_id" v:"required|min:1#股票池ID不能为空|股票池ID必须大于0"`
	StockCode string  `json:"stock_code" v:"required|length:6,10#股票代码不能为空|股票代码长度为6-10位"`
	Weight    float64 `json:"weight" v:"min:0|max:1#权重必须大于等于0|权重不能超过1"`
}

// BatchAddMemberReq 批量添加股票池成员请求
type BatchAddMemberReq struct {
	PoolId     int      `json:"pool_id" v:"required|min:1#股票池ID不能为空|股票池ID必须大于0"`
	StockCodes []string `json:"stock_codes" v:"required#股票代码列表不能为空"`
	Weight     float64  `json:"weight" v:"min:0|max:1#权重必须大于等于0|权重不能超过1"`
}

// PoolDetailRes 股票池详情响应
type PoolDetailRes struct {
	Pool    *entity.StockPool         `json:"pool"`
	Members []*entity.StockPoolMember `json:"members"`
	Rules   []*entity.StockPoolRule   `json:"rules"`
	Stats   *PoolStats                `json:"stats"`
}

// PoolStats 股票池统计信息
type PoolStats struct {
	MemberCount   int     `json:"member_count"`   // 成员数量
	UsageRate     float64 `json:"usage_rate"`     // 使用率
	TotalWeight   float64 `json:"total_weight"`   // 总权重
	AverageWeight float64 `json:"average_weight"` // 平均权重
}

// Create 创建股票池
func (s *StockPoolService) Create(ctx context.Context, req *CreatePoolReq) (*entity.StockPool, error) {
	// 验证股票池名称是否已存在
	exists, err := dao.StockPool.IsNameExists(ctx, req.Name)
	if err != nil {
		return nil, gerror.Wrap(err, "检查股票池名称失败")
	}
	if exists {
		return nil, gerror.New("股票池名称已存在")
	}

	// 构建股票池实体
	pool := &entity.StockPool{
		Name:        req.Name,
		Description: req.Description,
		Type:        req.Type,
		MaxSize:     req.MaxSize,
		IsActive:    true,
	}

	// 插入数据库
	id, err := dao.StockPool.Insert(ctx, pool)
	if err != nil {
		return nil, gerror.Wrap(err, "创建股票池失败")
	}

	// 返回创建的股票池信息
	pool.Id = int(id)
	g.Log().Info(ctx, "创建股票池成功", "id", id, "name", req.Name, "type", req.Type)
	return pool, nil
}

// Update 更新股票池
func (s *StockPoolService) Update(ctx context.Context, req *UpdatePoolReq) error {
	// 检查股票池是否存在
	existingPool, err := dao.StockPool.GetById(ctx, req.Id)
	if err != nil {
		return gerror.Wrap(err, "获取股票池信息失败")
	}
	if existingPool == nil {
		return gerror.New("股票池不存在")
	}

	// 检查名称是否与其他股票池冲突
	if existingPool.Name != req.Name {
		exists, err := dao.StockPool.IsNameExists(ctx, req.Name)
		if err != nil {
			return gerror.Wrap(err, "检查股票池名称失败")
		}
		if exists {
			return gerror.New("股票池名称已存在")
		}
	}

	// 构建更新数据
	updateData := &entity.StockPool{
		Name:        req.Name,
		Description: req.Description,
		MaxSize:     req.MaxSize,
	}

	if req.IsActive != nil {
		updateData.IsActive = *req.IsActive
	}

	// 更新数据库
	err = dao.StockPool.Update(ctx, req.Id, updateData)
	if err != nil {
		return gerror.Wrap(err, "更新股票池失败")
	}

	g.Log().Info(ctx, "更新股票池成功", "id", req.Id, "name", req.Name)
	return nil
}

// Delete 删除股票池
func (s *StockPoolService) Delete(ctx context.Context, id int) error {
	// 检查股票池是否存在
	pool, err := dao.StockPool.GetById(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "获取股票池信息失败")
	}
	if pool == nil {
		return gerror.New("股票池不存在")
	}

	// 删除股票池（包括成员和规则）
	err = dao.StockPool.Delete(ctx, id)
	if err != nil {
		return gerror.Wrap(err, "删除股票池失败")
	}

	g.Log().Info(ctx, "删除股票池成功", "id", id, "name", pool.Name)
	return nil
}

// GetById 根据ID获取股票池
func (s *StockPoolService) GetById(ctx context.Context, id int) (*entity.StockPool, error) {
	pool, err := dao.StockPool.GetById(ctx, id)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票池信息失败")
	}
	return pool, nil
}

// GetDetail 获取股票池详情
func (s *StockPoolService) GetDetail(ctx context.Context, id int) (*PoolDetailRes, error) {
	// 获取股票池基本信息
	pool, err := dao.StockPool.GetById(ctx, id)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票池信息失败")
	}
	if pool == nil {
		return nil, gerror.New("股票池不存在")
	}

	// 获取股票池成员
	members, err := dao.StockPoolMember.GetListByPoolId(ctx, id, 0, 0) // 不分页
	if err != nil {
		g.Log().Warning(ctx, "获取股票池成员失败", "id", id, "error", err)
		members = []*entity.StockPoolMember{}
	}

	// 获取股票池规则
	rules, err := dao.StockPoolRule.GetListByPoolId(ctx, id)
	if err != nil {
		g.Log().Warning(ctx, "获取股票池规则失败", "id", id, "error", err)
		rules = []*entity.StockPoolRule{}
	}

	// 计算统计信息
	stats := s.calculateStats(pool, members)

	return &PoolDetailRes{
		Pool:    pool,
		Members: members,
		Rules:   rules,
		Stats:   stats,
	}, nil
}

// GetList 获取股票池列表
func (s *StockPoolService) GetList(ctx context.Context, req *GetPoolListReq) (*PoolListRes, error) {
	// 设置默认值
	if req.Page == 0 {
		req.Page = 1
	}
	if req.Limit == 0 {
		req.Limit = 20
	}

	// 构建查询条件
	var conditions []interface{}
	if req.Keyword != "" {
		conditions = append(conditions, "(name LIKE ? OR description LIKE ?)", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
	}
	if req.Type != "" {
		condition := "type = ?"
		if len(conditions) > 0 {
			conditions[0] = fmt.Sprintf("%s AND %s", conditions[0], condition)
			conditions = append(conditions, req.Type)
		} else {
			conditions = append(conditions, condition, req.Type)
		}
	}
	if req.IsActive != nil {
		condition := "is_active = ?"
		if len(conditions) > 0 {
			conditions[0] = fmt.Sprintf("%s AND %s", conditions[0], condition)
			conditions = append(conditions, *req.IsActive)
		} else {
			conditions = append(conditions, condition, *req.IsActive)
		}
	}

	// 获取列表
	pools, err := dao.StockPool.GetList(ctx, req.Page, req.Limit, conditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票池列表失败")
	}

	// 获取总数
	total, err := dao.StockPool.GetCount(ctx, conditions...)
	if err != nil {
		return nil, gerror.Wrap(err, "获取股票池总数失败")
	}

	return &PoolListRes{
		List:  pools,
		Total: total,
		Page:  req.Page,
		Limit: req.Limit,
	}, nil
}

// AddMember 添加股票池成员
func (s *StockPoolService) AddMember(ctx context.Context, req *AddMemberReq) error {
	// 检查股票池是否存在
	pool, err := dao.StockPool.GetById(ctx, req.PoolId)
	if err != nil {
		return gerror.Wrap(err, "获取股票池信息失败")
	}
	if pool == nil {
		return gerror.New("股票池不存在")
	}

	// 检查股票是否存在
	stock, err := dao.Stock.GetByCode(ctx, req.StockCode)
	if err != nil {
		return gerror.Wrap(err, "获取股票信息失败")
	}
	if stock == nil {
		return gerror.New("股票不存在")
	}

	// 检查是否已在股票池中
	exists, err := dao.StockPoolMember.IsMemberExists(ctx, req.PoolId, req.StockCode)
	if err != nil {
		return gerror.Wrap(err, "检查股票池成员失败")
	}
	if exists {
		return gerror.New("股票已在股票池中")
	}

	// 检查股票池是否已满
	count, err := dao.StockPoolMember.GetCountByPoolId(ctx, req.PoolId)
	if err != nil {
		return gerror.Wrap(err, "获取股票池成员数量失败")
	}
	if count >= pool.MaxSize {
		return gerror.New("股票池已满")
	}

	// 添加成员
	member := &entity.StockPoolMember{
		PoolId:    req.PoolId,
		StockCode: req.StockCode,
		StockName: stock.Name,
		Weight:    req.Weight,
		AddedAt:   gtime.Now(),
	}

	_, err = dao.StockPoolMember.Insert(ctx, member)
	if err != nil {
		return gerror.Wrap(err, "添加股票池成员失败")
	}

	g.Log().Info(ctx, "添加股票池成员成功", "pool_id", req.PoolId, "stock_code", req.StockCode)
	return nil
}

// BatchAddMembers 批量添加股票池成员
func (s *StockPoolService) BatchAddMembers(ctx context.Context, req *BatchAddMemberReq) error {
	// 检查股票池是否存在
	pool, err := dao.StockPool.GetById(ctx, req.PoolId)
	if err != nil {
		return gerror.Wrap(err, "获取股票池信息失败")
	}
	if pool == nil {
		return gerror.New("股票池不存在")
	}

	// 检查股票池容量
	currentCount, err := dao.StockPoolMember.GetCountByPoolId(ctx, req.PoolId)
	if err != nil {
		return gerror.Wrap(err, "获取股票池成员数量失败")
	}
	if currentCount+len(req.StockCodes) > pool.MaxSize {
		return gerror.New("添加后将超过股票池最大容量")
	}

	// 验证股票代码并构建成员列表
	var members []*entity.StockPoolMember
	for _, stockCode := range req.StockCodes {
		// 检查股票是否存在
		stock, err := dao.Stock.GetByCode(ctx, stockCode)
		if err != nil {
			return gerror.Wrapf(err, "获取股票信息失败: %s", stockCode)
		}
		if stock == nil {
			return gerror.Newf("股票不存在: %s", stockCode)
		}

		// 检查是否已在股票池中
		exists, err := dao.StockPoolMember.IsMemberExists(ctx, req.PoolId, stockCode)
		if err != nil {
			return gerror.Wrapf(err, "检查股票池成员失败: %s", stockCode)
		}
		if exists {
			g.Log().Warning(ctx, "股票已在股票池中，跳过", "stock_code", stockCode)
			continue
		}

		member := &entity.StockPoolMember{
			PoolId:    req.PoolId,
			StockCode: stockCode,
			StockName: stock.Name,
			Weight:    req.Weight,
			AddedAt:   gtime.Now(),
		}
		members = append(members, member)
	}

	if len(members) == 0 {
		return gerror.New("没有有效的股票需要添加")
	}

	// 批量插入
	err = dao.StockPoolMember.BatchInsert(ctx, members)
	if err != nil {
		return gerror.Wrap(err, "批量添加股票池成员失败")
	}

	g.Log().Info(ctx, "批量添加股票池成员成功", "pool_id", req.PoolId, "count", len(members))
	return nil
}

// RemoveMember 移除股票池成员
func (s *StockPoolService) RemoveMember(ctx context.Context, poolId int, stockCode string) error {
	// 检查股票池是否存在
	pool, err := dao.StockPool.GetById(ctx, poolId)
	if err != nil {
		return gerror.Wrap(err, "获取股票池信息失败")
	}
	if pool == nil {
		return gerror.New("股票池不存在")
	}

	// 检查成员是否存在
	exists, err := dao.StockPoolMember.IsMemberExists(ctx, poolId, stockCode)
	if err != nil {
		return gerror.Wrap(err, "检查股票池成员失败")
	}
	if !exists {
		return gerror.New("股票不在股票池中")
	}

	// 删除成员
	err = dao.StockPoolMember.DeleteByPoolAndStock(ctx, poolId, stockCode)
	if err != nil {
		return gerror.Wrap(err, "移除股票池成员失败")
	}

	g.Log().Info(ctx, "移除股票池成员成功", "pool_id", poolId, "stock_code", stockCode)
	return nil
}

// GetMembers 获取股票池成员列表
func (s *StockPoolService) GetMembers(ctx context.Context, poolId, page, limit int) ([]*entity.StockPoolMember, int, error) {
	// 设置默认值
	if page == 0 {
		page = 1
	}
	if limit == 0 {
		limit = 20
	}

	members, err := dao.StockPoolMember.GetListByPoolId(ctx, poolId, page, limit)
	if err != nil {
		return nil, 0, gerror.Wrap(err, "获取股票池成员失败")
	}

	total, err := dao.StockPoolMember.GetCountByPoolId(ctx, poolId)
	if err != nil {
		return nil, 0, gerror.Wrap(err, "获取股票池成员总数失败")
	}

	return members, total, nil
}

// GetActivePools 获取激活的股票池列表
func (s *StockPoolService) GetActivePools(ctx context.Context) ([]*entity.StockPool, error) {
	pools, err := dao.StockPool.GetActivePools(ctx)
	if err != nil {
		return nil, gerror.Wrap(err, "获取激活股票池列表失败")
	}
	return pools, nil
}

// calculateStats 计算股票池统计信息
func (s *StockPoolService) calculateStats(pool *entity.StockPool, members []*entity.StockPoolMember) *PoolStats {
	memberCount := len(members)
	usageRate := float64(memberCount) / float64(pool.MaxSize)
	
	var totalWeight float64
	for _, member := range members {
		totalWeight += member.Weight
	}
	
	var averageWeight float64
	if memberCount > 0 {
		averageWeight = totalWeight / float64(memberCount)
	}

	return &PoolStats{
		MemberCount:   memberCount,
		UsageRate:     usageRate,
		TotalWeight:   totalWeight,
		AverageWeight: averageWeight,
	}
}